package drds.plus.sql_process.abstract_syntax_tree.node.query;

import drds.plus.common.jdbc.Parameters;
import drds.plus.sql_process.abstract_syntax_tree.ObjectCreateFactory;
import drds.plus.sql_process.abstract_syntax_tree.configuration.IndexMapping;
import drds.plus.sql_process.abstract_syntax_tree.execute_plan.ExecutePlan;
import drds.plus.sql_process.abstract_syntax_tree.execute_plan.query.QueryWithIndex;
import drds.plus.sql_process.abstract_syntax_tree.expression.item.function.Filter;
import drds.plus.sql_process.abstract_syntax_tree.expression.order_by.OrderBy;
import drds.plus.sql_process.abstract_syntax_tree.node.query.build.QueryBuilder;
import drds.plus.sql_process.abstract_syntax_tree.node.query.build.TableQueryWithIndexBuilder;
import drds.plus.sql_process.utils.Filters;
import drds.plus.sql_process.utils.OptimizerUtils;
import lombok.Getter;
import lombok.Setter;

import java.util.ArrayList;
import java.util.List;

public class TableQueryWithIndex extends TableQuery {
    @Setter
    @Getter
    private IndexMapping indexMapping = null;
    @Setter
    @Getter
    private String indexName = null;
    @Setter
    @Getter
    private TableQueryWithIndexBuilder basedOnIndexTableQueryNodeBuilder;

    public TableQueryWithIndex() {
        this(null);
    }

    public TableQueryWithIndex(String indexName) {
        super();
        this.indexName = indexName;
        basedOnIndexTableQueryNodeBuilder = new TableQueryWithIndexBuilder(this);
    }

    public void indexQueryKeyFilter(Filter filter) {
        this.setNeedBuild(true);
        this.indexQueryKeyFilter = filter;

    }

    public void indexQueryKeyFilter(String f) {
        this.setNeedBuild(true);
        this.indexQueryKeyFilter = Filters.createFilter(f);

    }

    public void resultFilter(Filter filter) {
        this.setNeedBuild(true);
        this.resultFilter = filter;

    }

    public void resultFilter(String filter) {
        this.setNeedBuild(true);
        this.resultFilter = Filters.createFilter(filter);

    }

    public QueryBuilder getQueryNodeBuilder() {
        return basedOnIndexTableQueryNodeBuilder;
    }

    public ExecutePlan toExecutePlan(int shareIndex) {
        subQueryToExecutePlan(shareIndex);
        QueryWithIndex queryWithIndex = ObjectCreateFactory.createQueryWithIndex();
        queryWithIndex.setAlias(this.getAlias());
        queryWithIndex.setSelectItemList(this.getSelectItemList());
        queryWithIndex.setConsistent(this.isConsistent());
        queryWithIndex.setGroupByList(this.getGroupByList());
        queryWithIndex.setIndexName(this.getIndexMapping() == null ? null : this.getIndexMapping().getIndexName());
        queryWithIndex.setKeyFilter(this.getIndexQueryKeyFilter());
        queryWithIndex.setValueFilter(this.getResultFilter());
        queryWithIndex.setLimitFrom(this.getLimitFrom());
        queryWithIndex.setLimitTo(this.getLimitTo());
        queryWithIndex.setLockMode(this.getLockMode());
        queryWithIndex.setOrderByList(this.getOrderByList());
        queryWithIndex.setSubQuery(null);
        queryWithIndex.setSql(this.getSql());
        queryWithIndex.setIsSubQuery(this.isSubQuery());
        queryWithIndex.having(this.getHaving());
        queryWithIndex.setExistAggregate(this.isExistAggregateExpression());
        queryWithIndex.setOtherJoinOnFilter(this.getOtherJoinOnFilter());
        queryWithIndex.setSubQueryFilter(this.getSubQueryFunctionFilter());
        queryWithIndex.setDataNodeId(this.getDataNodeId(shareIndex));
        String tableName = null;
        if (this.getActualTableName() != null) {
            tableName = this.getActualTableName(shareIndex);
        } else if (this.getIndexMapping() != null) {
            tableName = this.getIndexMapping().getIndexName();
        }
        queryWithIndex.setTableName(tableName);
        queryWithIndex.setSubQueryFilterId(this.getSubQueryId());
        queryWithIndex.setCorrelatedSubQuery(this.isCorrelatedSubQuery());
        queryWithIndex.setExistSequenceValue(this.isExistSequenceValue());
        return queryWithIndex;
    }

    public void build() {
        if (this.isNeedBuild()) {
            this.basedOnIndexTableQueryNodeBuilder.build();
        }

        setNeedBuild(false);
    }

    public String getTableName() {
        return this.getIndexMapping().getTableName();
    }

    public String getName() {
        if (this.getAlias() != null) {
            return this.getAlias();
        }

        return this.getIndexName();
    }

    public IndexMapping getIndexMappingUsed() {
        return this.getIndexMapping();
    }

    public TableQueryWithIndex copy() {
        TableQueryWithIndex tableQueryWithIndex = new TableQueryWithIndex(this.getIndexName());
        this.copySelfTo(tableQueryWithIndex);
        return tableQueryWithIndex;
    }

    protected void copySelfTo(Query query) {
        super.copySelfTo(query);
        TableQueryWithIndex tableQueryWithIndex = (TableQueryWithIndex) query;
        tableQueryWithIndex.indexMapping = indexMapping;
        tableQueryWithIndex.indexName = indexName;
        tableQueryWithIndex.setTableMetaData(this.getTableMetaData());
    }

    public TableQueryWithIndex deepCopy() {
        TableQueryWithIndex tableQueryWithIndex = new TableQueryWithIndex(this.getIndexName());
        this.deepCopySelfTo(tableQueryWithIndex);
        return tableQueryWithIndex;
    }

    protected void deepCopySelfTo(Query query) {
        super.deepCopySelfTo(query);
        TableQueryWithIndex tableQueryWithIndex = (TableQueryWithIndex) query;
        tableQueryWithIndex.indexMapping = indexMapping;
        tableQueryWithIndex.indexName = indexName;
        tableQueryWithIndex.setTableMetaData(this.getTableMetaData());
    }

    public void assignment(Parameters parameters) {
        super.assignment(parameters);
    }

    public List<OrderBy> getCompleteOrderByList() {
        List<OrderBy> orderByListCombinedWithGroupBy = getOrderByListCombinedWithGroupByList();
        if (orderByListCombinedWithGroupBy != null) {
            return orderByListCombinedWithGroupBy;
        }
        /**
         * 仅支持order by前缀匹配
         */
        List<OrderBy> orderByList = OptimizerUtils.getOrderByList(indexMapping);
        List<OrderBy> implicitOrderByList = new ArrayList<OrderBy>();
        for (int i = 0; i < orderByList.size(); i++) {
            orderByList.get(i).setTableName(this.getIndexName());
            if (this.getSelectItemList().contains(orderByList.get(i).getItem())) {
                implicitOrderByList.add(orderByList.get(i));
            } else {
                break;
            }
        }
        return implicitOrderByList;
    }


}
